home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / program / 441 / fplib20 / fp_prt.c < prev    next >
C/C++ Source or Header  |  1990-11-23  |  5KB  |  335 lines

  1. /* Modified:                            */
  2. /* DWB Apr 89    Handle unnormalized numbers            */
  3. /*        Fix exponent if .9... overflows            */
  4.  
  5. #define MAXEC    40
  6.  
  7. static char *f_buf;
  8. static int f_upper;
  9.  
  10. static char ec_buf[MAXEC+10];
  11. static int ec_sign, ec_exp;
  12.  
  13. fp_print(x, fmtc, prec, ptmp)
  14. float x;
  15. char *ptmp;
  16. {    register long    lx, m;
  17.     register int    e;
  18.  
  19. /* These routines have trouble with unnormalized numbers. */
  20.  
  21.     lx = *(long*)&x;
  22.     if ((m = lx & 0xffffff00L) == 0 || (e = lx & 0x7f) == 0)
  23.         x = 0.0;
  24.     else if (m > 0L)
  25.     {    do
  26.         {    if (--e == 0)
  27.             {    x = 0.0;
  28.                 goto uflo;
  29.             }
  30.             m <<= 1;
  31.         } while (m > 0L);
  32.         *(long*)&x = m | e | (lx & 0x80L);
  33. uflo:
  34.     }
  35.  
  36.     f_buf = ptmp;
  37.     f_upper = 0;
  38.  
  39.     switch (fmtc) {
  40.     case 'E':
  41.         f_upper = 1;
  42.     case 'e':
  43.         e_print(x, prec);
  44.         break;
  45.     case 'F':
  46.     case 'f':
  47.         f_print(x, prec);
  48.         break;
  49.     case 'G':
  50.         f_upper = 1;
  51.     case 'g':
  52.         g_print(x, prec);
  53.         break;
  54.     }
  55. }
  56.  
  57. static
  58. e_print(x, prec)
  59. float x;
  60. {
  61.     int nsig;
  62.     register char *p;
  63.  
  64.     if (prec < 0)
  65.         nsig = 7;
  66.     else
  67.         nsig = prec+1;
  68.  
  69.     ec_pr(x, nsig, 0);
  70.  
  71.     p = f_buf;
  72.     if (ec_sign)
  73.         *p++ = '-';
  74.     *p++ = ec_buf[0];
  75.     *p++ = '.';
  76.     if (nsig > 1)
  77.         strcpy(p, &ec_buf[1]);
  78.     p += strlen(p);
  79.     *p++ = f_upper ? 'E' : 'e';
  80.     ec_exp--;
  81.     if (ec_exp < 0) {
  82.         *p++ = '-';
  83.         ec_exp = -ec_exp;
  84.     }
  85.     if (ec_exp < 10)
  86.         *p++ = '0';
  87.     sprintf(p, "%d", ec_exp);
  88. }
  89.  
  90. static
  91. f_print(x, prec)
  92. float x;
  93. {
  94.     int nsig, nz, i;
  95.     register char *p;
  96.  
  97.     if (prec < 0)
  98.         nsig = 6;
  99.     else
  100.         nsig = prec;
  101.  
  102.     ec_pr(x, -nsig, 0);
  103.  
  104.     p = f_buf;
  105.     if (ec_sign)
  106.         *p++ = '-';
  107.     if (ec_exp < 1) {
  108.         *p++ = '0';
  109.     } else {
  110.         strncpy(p, ec_buf, ec_exp);
  111.         p += ec_exp;
  112.     }
  113.     if (prec != 0 || nsig)
  114.         *p++ = '.';
  115.     if (nsig == 0) {
  116.         *p = 0;
  117.         return;
  118.     }
  119.  
  120.     if (ec_exp < 0) {
  121.         nz = -ec_exp;
  122.         if (nz > nsig)
  123.             nz = nsig;
  124.         for (i=0; i<nz; i++)
  125.             *p++ = '0';
  126.         nsig -= nz;
  127.         if (nsig > 0) {
  128.             strncpy(p, ec_buf, nsig);
  129.             p += nsig;
  130.         }
  131.         *p = 0;
  132.     } else {
  133.         strcpy(p, &ec_buf[ec_exp]);
  134.     }
  135. }
  136.  
  137. static
  138. g_print(x, nsig)
  139. float x;
  140. {
  141.     int prec;
  142.  
  143.     if (nsig < 0)
  144.         nsig = 6;
  145.     if (nsig < 1)
  146.         nsig = 1;
  147.  
  148.     ec_pr(x, 1, 1);
  149.  
  150.     if (ec_exp < -3 || ec_exp > nsig)
  151.         e_print(x, nsig-1);
  152.     else {
  153.         prec = nsig - ec_exp;
  154.         f_print(x, prec);
  155.     }
  156. }
  157.  
  158. /*
  159.  * given x, ndig
  160.  *    if ndig is > 0, indicates number of significant digits
  161.  *    else -ndig is number of digits we want to the right of dec. pt.
  162.  * return the following:
  163.  *    appropriate number of digits of significance in ec_buf
  164.  *    ec_sign true if x was negative
  165.  *    ec_exp indicates the decimal point relative to leftmost digit
  166.  */
  167. static
  168. ec_pr(x, ndig, trunc)
  169. float x;
  170. {
  171.     int isneg;
  172.     int nhave;
  173.     long part;
  174.     int exp, newexp;
  175.     int ndigcpy = ndig;
  176.     float rem;
  177.     char tbuf[20];
  178.  
  179.     /* ndig must be >= 1 and <= MAXEC */
  180.     if (x < 0.0) {
  181.         isneg = 1;
  182.         x = -x;
  183.     } else
  184.         isneg = 0;
  185.  
  186.     /* get some digits */
  187.     somedig(x, &part, &rem, &exp);
  188.  
  189.     sprintf(ec_buf, "%ld", part);
  190.     nhave = strlen(ec_buf);
  191.     exp = nhave + exp;
  192.  
  193.     if (ndig <= 0) {
  194.         ndig = -ndig;
  195.         ndig += exp;
  196.     }
  197.  
  198.     if (ndig < 1)
  199.         ndig = 1;
  200.     else if (ndig > MAXEC)
  201.         ndig = MAXEC;
  202.  
  203.     /* get some more digits */
  204.     while (nhave < ndig+1 && nhave < MAXEC) {
  205.         if (rem == 0.0) {
  206.             while (nhave < ndig+1)
  207.                 ec_buf[nhave++] = '0';
  208.             ec_buf[nhave] = 0;
  209.             break;
  210.         }
  211.  
  212.         x = rem;
  213.         somedig(x, &part, &rem, &newexp);
  214.  
  215.         sprintf(tbuf, "%ld", part);
  216.         newexp = strlen(tbuf) + newexp;
  217.         while (newexp++)
  218.             ec_buf[nhave++] = '0';
  219.         strcpy(&ec_buf[nhave], tbuf);
  220.         nhave = strlen(ec_buf);
  221.     }
  222.  
  223.     if (fround(ndig, trunc))
  224.     {    if (ndigcpy <= 0)
  225.             strcpy(ec_buf+ndig, "0");
  226.         exp++;
  227.     }
  228.  
  229.     ec_sign = isneg;
  230.     ec_exp = exp;
  231. }
  232.  
  233. static
  234. fround(n, trunc)
  235. {
  236.     char *p;
  237.     int oflo = 0;
  238.  
  239.     p = &ec_buf[n];
  240.     if (*p >= '5' && !trunc) {
  241.         p--;
  242.         while (p >= ec_buf) {
  243.             *p += 1;
  244.             if (*p < '9')
  245.                 goto done;
  246.             *p = '0';
  247.             p--;
  248.         }
  249.         ec_buf[0] = '1';
  250.         oflo = 1;
  251.     }
  252. done:
  253.     ec_buf[n] = 0;
  254.     return oflo;
  255. }
  256.  
  257. static
  258. somedig(x, lp, remp, expp)
  259. float x;
  260. long *lp;
  261. float *remp;
  262. int *expp;
  263. {
  264.     int bexp, dexp;
  265.     long ipart;
  266.     float rem;
  267.  
  268.     bexp = fgetexp(x);
  269.     dexp = 0;
  270.  
  271.     while (bexp > 31) {
  272.         x *= 1E-3;
  273.         dexp += 3;
  274.         bexp = fgetexp(x);
  275.     }
  276.     while (bexp < 10) {
  277.         x *= 1E3;
  278.         dexp -= 3;
  279.         if (dexp < -24) {
  280.             ipart = 0;
  281.             dexp = 0;
  282.             rem = 0.0;
  283.             goto iszero;
  284.         }
  285.         bexp = fgetexp(x);
  286.     }
  287.     fsplit(x, &ipart, &rem);
  288. iszero:
  289.     *lp = ipart;
  290.     *remp = rem;
  291.     *expp = dexp;
  292. }
  293.  
  294. static
  295. fgetexp(x)
  296. float x;
  297. {
  298.     char *p;
  299.     int i;
  300.  
  301.     p = (char *)&x;
  302.     i = p[3] & 0x7f;
  303.     i -= 0x40;
  304.     return i;
  305. }
  306.  
  307. static
  308. fsplit(x, vp, rp)
  309. float x, *rp;
  310. long *vp;
  311. {
  312.     long ival;
  313.     float rem;
  314.     int bexp, neg;
  315.  
  316.     ival = *(long *)&x;
  317.     neg = ival & 0x80;
  318.     ival &= ~0xff;
  319.  
  320.     bexp = fgetexp(x);
  321.  
  322.     if (bexp < 1) {
  323.         ival = 0;
  324.         rem = x;
  325.     } else {
  326.         ival = (unsigned long)ival >> (32-bexp);
  327.         if (neg)
  328.             ival = -ival;
  329.         rem = x - (float)ival;
  330.     }
  331.  
  332.     *vp = ival;
  333.     *rp = rem;    
  334. }
  335.